package compiler.my_parser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by szj on 2017/5/30.
 */
public class ProductionManager {

    private static ProductionManager instance;
    private Map<Integer, List<Production>> productionMap = new HashMap<>();

    public static ProductionManager getInstance() {
        if (instance == null) {
            instance = new ProductionManager();
        }
        return instance;
    }

    //s -> e
    //e -> e + t
    //e -> t
    //t -> t * f
    //t -> f
    //f -> ( e )
    //f->NUM
    public ProductionManager initProductions() {
        int prodNum = 1;
        addProduction(new Production(prodNum, 0,
                SymbolDefinition.STATEMENT.ordinal(),
                new int[]{SymbolDefinition.EXPR.ordinal()}));
        prodNum++;

        addProduction(new Production(prodNum, 0,
                SymbolDefinition.EXPR.ordinal(),
                new int[]{SymbolDefinition.EXPR.ordinal(), SymbolDefinition.PLUS.ordinal(), SymbolDefinition.TERM.ordinal()}));
        prodNum++;

        addProduction(new Production(prodNum, 0, SymbolDefinition.EXPR.ordinal(),
                new int[]{SymbolDefinition.TERM.ordinal()}));
        prodNum++;

        addProduction(new Production(prodNum, 0,
                SymbolDefinition.TERM.ordinal(),
                new int[]{SymbolDefinition.TERM.ordinal(), SymbolDefinition.TIMES.ordinal(), SymbolDefinition.FACTOR.ordinal()}));
        prodNum++;

        addProduction(new Production(prodNum, 0,
                SymbolDefinition.TERM.ordinal(),
                new int[]{SymbolDefinition.FACTOR.ordinal()}));
        prodNum++;

        addProduction(new Production(prodNum, 0,
                SymbolDefinition.FACTOR.ordinal(),
                new int[]{SymbolDefinition.LEFT_PAREN.ordinal(), SymbolDefinition.EXPR.ordinal(), SymbolDefinition.RIGHT_PAREN.ordinal()}));
        prodNum++;

        addProduction(new Production(prodNum, 0,
                SymbolDefinition.FACTOR.ordinal(),
                new int[]{SymbolDefinition.NUM_OR_ID.ordinal()}));

        return instance;
    }

    private void addProduction(Production production) {
        if (!productionMap.containsKey(production.getLeftPortion())) {
            productionMap.put(production.getLeftPortion(), new ArrayList<Production>() {{
                add(production);
            }});
            return;
        }

        productionMap.get(production.getLeftPortion()).add(production);
    }

    public List<Production> getProduction(int leftPortion) {
        return productionMap.get(leftPortion);
    }

    public ProductionManager printProductions() {
        this.productionMap.entrySet().forEach(productionMap -> {
            productionMap.getValue().forEach(Production::println);
        });

        return instance;
    }

    public ProductionManager doFirstSet() {
        new FirstSetBuilder().doFirstSet();
        return instance;
    }
}
